/* */
package com.zhiwei.msf.common.interceptor;

import java.lang.reflect.Method;
import java.util.Locale;
import java.util.Optional;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.http.MediaType;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.zhiwei.msf.common.annotation.IgnoreSecurity;
import com.zhiwei.msf.common.config.SecurityContext;
import com.zhiwei.msf.common.constant.CommonErrorConstants;
import com.zhiwei.msf.common.constant.HttpConstants;
import com.zhiwei.msf.common.constant.ResultResponseMsg;
import com.zhiwei.msf.common.service.GatewayService;

import lombok.extern.slf4j.Slf4j;

/**
 * @function:
 * @author zhiwei.yang
 * @time 2022年7月8日-下午7:01:09
 */
@Slf4j
@Component
public class SecurityInterceptor implements HandlerInterceptor {

	@Autowired
	private GatewayService gatewayService;

	@Autowired
	private MessageSource messageSource;

	@SuppressWarnings("deprecation")
	@Override
	public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse response, Object handler)
			throws Exception {
		if (handler instanceof HandlerMethod) {
			Method method = ((HandlerMethod) handler).getMethod();
			IgnoreSecurity ignoreSecurity = AnnotationUtils.getAnnotation(method, IgnoreSecurity.class);
			if (ignoreSecurity == null || ignoreSecurity.value()) {
				log.info("白名单接口无需验证：{}", httpServletRequest.getRequestURI());
				return true;
			}
		}
		String requestUri = httpServletRequest.getRequestURI();
		String requestIp = httpServletRequest.getRemoteAddr();
		String requestToken = Optional.ofNullable(httpServletRequest.getHeader(HttpConstants.HEADER_TOKEN))
				.orElse(httpServletRequest.getParameter(HttpConstants.HEADER_TOKEN));

		String origin = httpServletRequest.getHeader(HttpConstants.HEADER_ORIGIN);
		log.info("客户端【{}:{}】访问URL:{},请求Token:{}, request ===> {}", requestIp, origin, requestUri, requestToken,
				JSON.toJSONString(httpServletRequest.getParameterMap()));

		if (isWhiteUrl(requestUri)) {
			log.info("请求路径【{}】在白名单，无需验证Token", requestUri);
			return true;
		}

		String username = this.checkToken(requestToken);
		if (!StringUtils.hasText(username)) {
			log.error("请求路径【{}:{}】Token校验失败，请使用正确Token访问", requestUri, requestToken);
			ResultResponseMsg resultResponseMsg = ResultResponseMsg.buildResultMsg(CommonErrorConstants.HTTP_TOKEN,
					messageSource.getMessage(CommonErrorConstants.HTTP_TOKEN, null, Locale.getDefault()), null);
			response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
			response.getWriter().println(JSON.toJSONString(resultResponseMsg, SerializerFeature.WriteMapNullValue));
			response.getWriter().flush();
			response.getWriter().close();
			return false;
		}
		SecurityContext.setUsername(username);
		return true;
	}

	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
			@Nullable Exception ex) throws Exception {
		SecurityContext.clear();
	}

	/**
	 * 校验请求地址是否是白名单
	 *
	 * @param requestUri
	 * @return
	 */
	private boolean isWhiteUrl(String requestUri) {
		if (StringUtils.isEmpty(requestUri)) {
			return false;
		}
		return gatewayService.checkWhiteUrl(requestUri);
	}

	/**
	 * 校验请求Token(服务网关校验)
	 *
	 * @param token
	 * @return
	 */
	private String checkToken(String token) {
		return gatewayService.checkToken(token);
	}

}
